class FileGenerator:
    """ Generator feature file for training """
    def __init__(self, fileType = None):
        if fileType != None:
            self._fileType = fileType.lower().title()
            generatorName = "generate" + self._fileType
            self._generateFile = getattr(self, generatorName)
        
    def generateFile(self, outputPath, fromMatrixFilename, \
                               reducedDimWordList, binaryClassList, dataNodeDict, filename, attachment, isFast, console):
        extendName = ".%s"%self._fileType.lower()
        vectorFilename = outputPath + "/" + filename + extendName
        reducedDimWordList.sort()
        self._generateFile(vectorFilename, fromMatrixFilename, reducedDimWordList, binaryClassList, dataNodeDict, attachment, isFast, console)
    
    def generateArff(self, vectorFilename, fromMatrixFilename, \
                               reducedDimWordList, binaryClassList, dataNodeDict, filename):
        header = self._generateArffHeaderList(binaryClassList, reducedDimWordList)
        vectorFilename = vectorFilename
        fileWriter = open(vectorFilename, "w+")
        srcReader = open(fromMatrixFilename, "rU")
        print "Now generating attribute-file \'%s\'"%vectorFilename
        try:            
            fileWriter.write("\n".join(header))
            #lineElementList = srcReader.readline()[:-1].split(',')
            lineElementList = srcReader.readline().strip().split(',')
            wordIndexList = []
            for word in reducedDimWordList:
                wordIndexList.append(lineElementList.index(word))
            #wordIndexIter = (lineElementList.index(w) for w in reducedDimWordList)
            # <write out the DATA section>     
            for line in srcReader:
                #lineElementList = line[:-1].split(',')
                lineElementList = line.strip().split(',')
                nodeID = int(lineElementList[0])                
                data = [lineElementList[i] for i in wordIndexList]
                if binaryClassList[0] in dataNodeDict[nodeID].classFreqDist:            
                    data.append(binaryClassList[0])
                else: data.append(binaryClassList[1])                
                #data.insert(0,("%d -- "%nodeID))##delete this                               
                fileWriter.write(','.join(["%s"%d for d in data]) + '\n')
            # </write out the ARFF data>
        finally: 
            srcReader.close()
            fileWriter.close()
        return
    
    def _generateArffHeaderList(self, binaryClassList, attributeList):
                
        ## <write out the ARFF header>
        header = []
        header.append("@RELATION \"test class %s\""%binaryClassList[0])
        [header.append("@ATTRIBUTE \"%s\" NUMERIC" %(attr)) for attr in attributeList]            
        header.append("@ATTRIBUTE class {%s}" %(",".join(["\"%s\""%c for c in binaryClassList])))
        header.append("@DATA\n")
        return header
    
    def generateDat(self, vectorFilename, fromMatrixFilename, \
                               reducedDimWordList, binaryClassList, dataNodeDict, attachment, isFast=False, console = None): 
        if isFast:
            print "Now generating attribute-file \'%s\'"%vectorFilename
            indexMethod = console.xmlConf.getIndexMethod()
            indexer = console.instFact.getIndexer(indexMethod)            
            fileWriter = open(vectorFilename, 'w+') 
            wordsFile = vectorFilename + '-words.txt'
            wordsWriter = open(wordsFile, 'w+')
            try:                          
                wordsWriter.write('\n'.join(reducedDimWordList))                                          
                nodeIDs = dataNodeDict.keys()
                nodeIDs.sort()
                print "--- start building VectorMaxtrix (%d attributes) ... "%len(nodeIDs)                
                dataMatrix = []
                for nodeID in nodeIDs: 
                    data = []           
                    indexDict = indexer._index(dataNodeDict[nodeID], attachment)                    
                    for i in xrange(len(reducedDimWordList)):
                        key = reducedDimWordList[i]
                        if key in dataNodeDict[nodeID].wordsFreqDist:
                            data.append("%s:%s"%(i+1, str(indexDict[key])))
                    if binaryClassList[0] in dataNodeDict[nodeID].classFreqDist:
                        #fileWriter.write('+1 ' + ' '.join(["%s"%d for d in data]) + '\n')
                        dataMatrix.append('+1 ' + ' '.join(["%s"%d for d in data])) 
                    else: 
                        #fileWriter.write('-1 ' + ' '.join(["%s"%d for d in data]) + '\n')   
                        dataMatrix.append('-1 ' + ' '.join(["%s"%d for d in data])) 
                fileWriter.write('\n'.join(dataMatrix))
                                                           
            finally: 
                fileWriter.close()
                wordsWriter.close()
            return      
            
        else:
            vectorFilename = vectorFilename
            fileWriter = open(vectorFilename, "w+")
            wordsFile = vectorFilename + '-words.txt'
            wordsWriter = open(wordsFile, 'w+')
            srcReader = open(fromMatrixFilename, "rU")
            print "Now generating attribute-file \'%s\'"%vectorFilename
            try:            
                wordsWriter.write('\n'.join(reducedDimWordList))
                lineElementList = srcReader.readline().strip().split(',')
                #lineElementList = srcReader.readline()[:-1].split(',')
                wordIndexList = []
                for word in reducedDimWordList:
                    wordIndexList.append(lineElementList.index(word))
                # <write out the DATA section>       
                for line in srcReader:
                    data = []
                    lineElementList = line.strip().split(',')
                    #lineElementList = line[:-1].split(',')
                    nodeID = int(lineElementList[0])
                    rawDataList = [lineElementList[i] for i in wordIndexList]
                    indexLength = len(rawDataList)                
                    for i in range(indexLength):                    
                        if float(rawDataList[i]) != 0:
                            data.append("%s:%s"%(i+1, rawDataList[i]))
                    if binaryClassList[0] in dataNodeDict[nodeID].classFreqDist:            
                        data.insert(0, '+1')
                    else: 
                        data.insert(0, '-1')                
                    #data.insert(0,("%d -- "%nodeID))##delete this
                    fileWriter.write(' '.join(["%s"%d for d in data]) + '\n')            
                # </write out the ARFF data>
            finally: 
                srcReader.close()
                fileWriter.close()
                wordsWriter.close()
            return
        
    
    
    def readDatWords(self, datWordFile):
        return open(datWordFile, 'rU').read().split()
    
    def generateArffHeaderFromDat(self, attributeList, datFilename):
                
        ## <write out the ARFF header>
        header = []
        header.append("@RELATION \"Converted from DAT file: %s\""%datFilename)
        [header.append("@ATTRIBUTE \"%s\" NUMERIC" %(attr)) for attr in attributeList]            
        header.append("@ATTRIBUTE class {+1, -1}") 
        header.append("@DATA\n")
        return header
    
    def generateDataFromDat(self, datDataFilename, attributeLength):
        data = []
        try:
            datasrc = open(datDataFilename)
            for line in datasrc:
                dataLine = ['0']*attributeLength
                elements = line.split()
                klass = elements[0]
                for element in elements[1:]:
                    (id, value) = element.split(':')
                    dataLine[int(id)-1] = value
                dataLine.append(klass)
                data.append(dataLine)
        finally:
            datasrc.close()
        return data
            
    
    def dat2arff(self, datDataFilename, datWordFilename, arffFilename = None):
        attributes = open(datWordFilename, 'rU').read().split()
        header = self.generateArffHeaderFromDat(attributes, datDataFilename)
        data = self.generateDataFromDat(datDataFilename, len(attributes))
        if arffFilename == None:
            import os
            base = os.path.splitext(datDataFilename)[0]
            arffFilename = "%s.%s"%(base, 'arff')
        open(arffFilename, "w+").write('\n'.join(header))
        open(arffFilename, "a+").write('\n'.join([','.join(line) for line in data]))
        
        
if __name__ == "__main__":
    import sys
    datFile = sys.argv[1]
    datWords = sys.argv[2]
    fg = FileGenerator()
    fg.dat2arff(datFile, datWords)
        
        
    
    
